package com.wyman.beans.factory.support;

import cn.hutool.core.util.StrUtil;
import com.wyman.beans.BeanException;
import com.wyman.beans.PropertyValue;
import com.wyman.beans.PropertyValues;
import com.wyman.beans.factory.*;
import com.wyman.beans.factory.config.*;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Author 李伟民
 * @Description DateTime 2024/11/25 01:43
 */

//6 12.11 新增对AutowireCapableBeanFactory接口中定义的真正执行bean初始化前后方法的实现
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {

        Object bean;
        //3. 修改真正创建bean的动作
        //bean =  beanDefinition.getBeanClass().newInstance();
        //12. 判断对象是否需要代理 如果需要代理则直接返回代理的bean对象
        bean = resolveBeforeInstantiation(beanName,beanDefinition);
        if(null!=bean){
            return bean;
        }

        bean = createBeanInstance(beanDefinition,beanName,args);

        //4. 增加给bean的属性赋值
        applyPropertyValues(beanName,bean,beanDefinition);

        //12.11 6. 真正将bean实例添加到容器之前进行处理 包括前置处理 初始化操作 后置处理
        bean = initializeBean(beanName,bean,beanDefinition);

        //12.12 7 注册需要销毁的bean到销毁beanMap中
        registerDisposableBeanIfNecessary(beanName,bean,beanDefinition);


        //12.14如果不是单例 不需要存到Map中 每次获取都重新创建
        //负责管理实例化的bean
        if(beanDefinition.isSingleton()) {
            addSingleton(beanName, bean);
        }
        return bean;
    }

    //4.新增
    private void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {

        PropertyValues propertyValues = beanDefinition.getPropertyValues();
        Class<?> clazz = beanDefinition.getBeanClass();

        try {
            for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {

                Object value = propertyValue.getValue();
                Field field = clazz.getDeclaredField(propertyValue.getName());
                //用于获取递归拿到的bean对象值
                Object recBean = null;

                //如果属性也是对象 递归实例化
                if(value instanceof BeanReference){
                    recBean = getBean(((BeanReference) value).getBeanName());
                    //使用反射设置属性值 不用工具类
                    field.setAccessible(true);
                    field.set(bean,recBean);

                }
                //如果是基本类型 则直接用value设置值
                else {
                    field.setAccessible(true);
                    field.set(bean,value);
                }

            }
        }
        catch (NoSuchFieldException | IllegalAccessException  e) {
            throw new BeanException("设置Bean属性值失败！"+beanName);
        }
    }

    //根据args找到合适的构造器 调用instantiationStrategy中的实例化方法创建bean
    private Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {

        Object bean = null;

        //空参情况
        if(args==null){
           return instantiationStrategy.instantiate(beanDefinition,beanName,null,null);
        }

        //带参情况
        Class<?> clazz = beanDefinition.getBeanClass();
        for(Constructor ctor:clazz.getDeclaredConstructors()){

           if(ctor.getParameterTypes().length == args.length){
             bean =  getInstantiationStrategy().instantiate(beanDefinition, beanName, ctor, args);
           }
        }

        return bean;
    }

    public InstantiationStrategy getInstantiationStrategy(){
        return this.instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy){
        this.instantiationStrategy = instantiationStrategy;
    }


    private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition)  {


        //12.14 8 根据支持的aware接口情况 向bean对象中设置相应的对象
        if(bean instanceof Aware){
            if(bean instanceof BeanNameAware){
                ((BeanNameAware)bean).setBeanName(beanName);
            }
            if(bean instanceof BeanFactoryAware){
                ((BeanFactoryAware)bean).setBeanFactory(this);
            }
            if(bean instanceof BeanClassLoaderAware){
                ((BeanClassLoaderAware)bean).setBeanClassLoader(bean.getClass().getClassLoader());
            }

        }

        //前置处理 传beanName和bean对象 对应接口AutowireCapableBeanFactory中的 before方法
        Object wrapperBean = applyBeanPostProcessorsBeforeInitialization(bean,beanName);
        //初始处理 传beanName和bean对象和BeanDefinition
        invokeInitMethods(beanName,wrapperBean,beanDefinition);
        //后置处理 传beanName和bean对象 对应接口AutowireCapableBeanFactory中的 after方法
        wrapperBean = applyBeanPostProcessorsAfterInitialization(wrapperBean,beanName);
        return wrapperBean;
    }

    //实现接口 before方法 存储处理器的列表在父类中 父类还提供了获取列表方法
    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean,String beanName) throws BeanException{
        Object res = existingBean;
        for(BeanPostProcessor beanPostProcessor:getBeanPostProcessors()) {
            Object cur = beanPostProcessor.postProcessBeforeInitialization(res, beanName);
            if (cur == null) {
                return res;
            }
            res = cur;
        }
        return res;
    }

    //实现接口 after方法
    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeanException {
        Object res = existingBean;
        for(BeanPostProcessor beanPostProcessor:getBeanPostProcessors()){
            Object cur = beanPostProcessor.postProcessAfterInitialization(res,beanName);
            if(cur==null){
                return res;
            }
            res = cur;
        }
        return res;
    }

    //初始处理
    public void invokeInitMethods(String beanName, Object wrapperBean, BeanDefinition beanDefinition)  {

        //实现接口的话 执行接口中的的afterPropertiesSet()方法
        if(wrapperBean instanceof InitializingBean){
            try {
                ((InitializingBean)wrapperBean).afterPropertiesSet();
            } catch (Exception e) {
                throw new BeanException(beanName+": 执行初始化方法失败!");
            }
        }
        ///执行配置信息中 init-method方法
        String initMethodName = beanDefinition.getInitMethodName();
       // System.out.println("获取到了配置信息中的初始化方法："+initMethodName);
        if(StrUtil.isNotEmpty(initMethodName)){
            //使用反射根据方法名称获得方法
            Method initMethod = null;
            try {
                initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
            if(initMethod==null){
                throw new BeanException("cant find init method name: "+initMethodName+" with bean name"+beanName);
            }
            try {
                initMethod.invoke(wrapperBean);
                System.out.println("执行了初始化方法");
            } catch (IllegalAccessException|InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }
    }

    //如果bean是原型作用域 即使实现了销毁接口或者配置了销毁方法信息 也不会执行销毁 因为不会放到销毁的Map中 防止空指针异常
    public void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition){
        if(beanDefinition.isPrototype()){
            return;
        }

        if(bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())){
            registerDisposableBean(beanName,new DisposableBeanAdapter(bean,beanName,beanDefinition));
        }
    }

    //12 遍历所有前处理器 找到处理代理的前处理器 并调用其中创建代理的方法
    public Object applyBeanPostProcessorBeforeInstantiation(Class<?> beanClass,String beanName) throws  BeanException{
        for(BeanPostProcessor beanPostProcessor:getBeanPostProcessors()){
            if(beanPostProcessor instanceof InstantiationAwareBeanPostProcessor){
                //会根据bean类型动态创建代理对象 如果不匹配切点表达式或者匹配的和实现代理有关的 那么不创建 返回null
               Object result =  ((InstantiationAwareBeanPostProcessor)beanPostProcessor).postProcessBeforeInstantiation(beanClass,beanName);
               if(null!=result){
                   return result;
               }
            }
        }
        return null;
    }

    //12 这里是如果bean应该被代理 代理之后执行其它后处理器中 初始化好bean之后的后置操作
    public Object resolveBeforeInstantiation(String beanName,BeanDefinition beanDefinition){
           Object bean =  applyBeanPostProcessorBeforeInstantiation(beanDefinition.getBeanClass(),beanName);
           if(bean!=null){
               bean = applyBeanPostProcessorsAfterInitialization(bean,beanName);
           }
           return bean;
    }
}
